using AdminApiTemplate.Common.Helpers;
using System.Data;
using System.Diagnostics;
using System.Reflection;

namespace AdminApiTemplate.Tasks
{
    public class BaseTaskHelper
    {
        private readonly MySqlHelper _defaultQuery;

        private readonly TaskService _taskService;

        public BaseTaskHelper(
            MySqlHelper defaultQuery)
        {
            _defaultQuery = defaultQuery;
            _taskService=new TaskService(_defaultQuery);
        }

        public void Run()
        {
            var assembly = Assembly.Load("AdminApiTemplate.Tasks");
            var types = assembly.GetTypes().ToList();
            for (var i = types.Count - 1; i >= 0; i--)
            {
                var ttype = types[i];
                if (ttype.Name == nameof(ITask))
                {
                    types.RemoveAt(i);
                }

                if (!typeof(ITask).IsAssignableFrom(ttype))
                {
                    types.RemoveAt(i);
                }
            }

            var tasks = _taskService.GetCanExecuteTaskList();
            if (tasks.Any())
            {
                var tasksStartup = tasks.Where(w => w.RunWhenStartup.GetValueOrDefault());
                if (tasksStartup.Any())
                {
                    Run(types, tasksStartup.ToArray());
                }

                //var tasksNotStartup = tasks.Where(w => !w.RunWhenStartup.GetValueOrDefault());
                //if (tasksNotStartup.Any())
                //{
                //    foreach (var task in tasksNotStartup)
                //    {
                //        UpdateNextExecuteTime(task);
                //    }
                //}
            }

            while (true)
            {
                try
                {
                    var tasksNext = _taskService.GetNextTaskList();
                    if (tasksNext.Any())
                    {
                        Run(types, tasksNext.ToArray());
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteError(ex.ToString());
                }
                Thread.Sleep(5000);
            }
        }

        private void Run(List<Type> types, params GetNextTaskListResponseItem[] tasks)
        {
            if (tasks != null && tasks.Count() > 0)
            {
                foreach (var task in tasks)
                {
                    if (string.IsNullOrEmpty(task.ExecuteType))
                    {
                        LogHelper.WriteAsync($"[{task.Name}]未设置ExecuteType，将不会执行", "Task");
                        continue;
                    }

                    var ttype = types.Where(w => w.FullName.ToLower() == task.TypeName.ToLower()).FirstOrDefault();
                    if (ttype == null)
                    {
                        continue;
                    }

                    var tmethod = ttype.GetMethod("Execute");
                    if (tmethod == null)
                    {
                        continue;
                    }

                    //更新下次执行时间
                    UpdateNextExecuteTime(task);

                    var args = new object[] { _defaultQuery };
                    var type_obj = Activator.CreateInstance(ttype, args);
                    TaskHelper.RunUseThread(() =>
                    {
                        RealRun(task, tmethod, type_obj);
                    });
                }
            }
        }

        private void RealRun(GetNextTaskListResponseItem task, MethodInfo tmethod, object type_obj)
        {
            var log = new AddExecuteLogRequest
            {
                TaskId = task.Id,
                TaskName = task.Name,
                Success = false
            };
            var sw = new Stopwatch();
            sw.Start();
            try
            {
                tmethod.Invoke(type_obj, new object[] { });
                log.Success = true;
            }
            catch (Exception ex)
            {
                if (ex.InnerException!=null)
                {
                    LogHelper.WriteErrorAsync(ex.InnerException.ToString());
                    log.Message = ex.InnerException.Message;
                }
                else
                {
                    LogHelper.WriteErrorAsync(ex.ToString());
                    log.Message = ex.Message;
                }
            }
            sw.Stop();

            log.CostTime = sw.ElapsedMilliseconds;
            _taskService.AddExecuteLog(log);
        }

        /// <summary>
        /// 更新下次执行时间
        /// </summary>
        /// <param name="task"></param>
        private void UpdateNextExecuteTime(GetNextTaskListResponseItem task)
        {
            var parts = task.ExecuteType.Split(':');
            if (parts.Length != 2)
            {
                return;
            }

            var nextExecuteTime = default(DateTime?);
            var executeType = ConvertHelper.GetInt(parts[0]);
            switch (executeType)
            {
                case (int)ExecuteTypeEnum.Interval:
                    {
                        var seconds = ConvertHelper.GetInt(parts[1]);
                        if (seconds.HasValue)
                        {
                            nextExecuteTime = DateTime.Now.AddSeconds(seconds.GetValueOrDefault());
                        }
                        break;
                    }
                case (int)ExecuteTypeEnum.Daily:
                    {
                        var seconds = ConvertHelper.GetInt(parts[1]);
                        if (seconds.HasValue)
                        {
                            var ts = TimeSpan.FromSeconds(seconds.GetValueOrDefault());
                            nextExecuteTime = DateTime.Now.AddDays(1).Date.AddSeconds(ts.TotalSeconds);
                        }
                        break;
                    }
            }

            if (nextExecuteTime.HasValue)
            {
                _taskService.UpdateNextExecuteTime(task.Id.GetValueOrDefault(), nextExecuteTime.GetValueOrDefault());
            }
        }
    }
}
